package org.haredot.aspect;

import com.alibaba.fastjson2.JSONArray;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.haredot.annotation.LogModule;
import org.haredot.config.ServiceLogType;
import org.haredot.constant.RabbitConst;
import org.haredot.context.LogContextHolder;
import org.haredot.entity.ServiceLog;
import org.haredot.utils.IpUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Objects;

@Aspect
@Component
@EnableConfigurationProperties(value= ServiceLogType.class)
public class ServiceLogAspectj {

    @Resource
    private HttpServletRequest request ;

    @Resource
    private RabbitTemplate rabbitTemplate ;

    @Resource
    private ServiceLogType serviceLogType ;

    @Pointcut("execution(* org.haredot.controller.*.*(..)) && !within(org.haredot.controller.LoggerController)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        ServiceLog log = LogContextHolder.getLog();
        // 设置请求方式
        log.setMethod(request.getMethod());
        // 设置操作人员
        log.setUser(SecurityContextHolder.getContext().getAuthentication().getName());
        // 设置请求地址
        log.setPath(request.getRequestURI());
        // 设置 请求的 控制层方法名
        //joinPoint.getTarget().getClass().getName()
        log.setMethodName(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
        // 设置 请求的参数
        log.setParams(JSONArray.toJSONString(joinPoint.getArgs()));
        // 设置 操作的时间
        log.setCreateTime(LocalDateTime.now());

        String ipAddress = IpUtils.getIpAddress(request);
        // 获取 IP地址
        log.setIp(ipAddress);
        log.setAddress(IpUtils.getRealAddress(ipAddress));

        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        String browserName = userAgent.getBrowser().getName();
        log.setBrowserName(browserName);

        String osName = userAgent.getOperatingSystem().getName();
        log.setOsName(osName);

        // 获取 目标类上的注解
        if (joinPoint.getTarget().getClass().isAnnotationPresent(LogModule.class)) {
            LogModule logModule = joinPoint.getTarget().getClass().getAnnotation(LogModule.class);
            log.setModule(logModule.value());
        }

    }

    @AfterReturning(value = "pointcut()", returning = "ret")
    public void afterReturning(Object ret) {
        ServiceLog log = LogContextHolder.getLog();
        if (serviceLogType.isResult()) log.setResultVo(JSONArray.toJSONString(ret));
        log.setStatus(true);
    }

    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(Exception e) {
        ServiceLog log = LogContextHolder.getLog();
        log.setStatus(false);
        log.setMessage(e.getMessage());
    }

    @After("pointcut()")
    public void after() {
        try {
            // 是否是允许 记录的 请求类型
            if (serviceLogType.getTypes().stream().anyMatch(type -> Objects.equals(type.name(), request.getMethod()))) {

                ServiceLog log = LogContextHolder.getLog();
                // 将数据 写入 到 rabbit 中，以实现 异步解耦操作
                rabbitTemplate.convertAndSend(RabbitConst.HAREDOT_LOG_EXCHANGE, "haredot.service.log", log);
            }

        } catch (AmqpException e) {
            e.printStackTrace();
        } finally {
            // 负责将收集到的数据，写入到数据库
            LogContextHolder.remove();
        }
    }

}
